#include <linux/init.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "platform_data_special.h"

struct stm32mp157a{
	unsigned int major;
	struct resource *resource;
	struct class *cls;
	struct device *dev;
	unsigned int *mdr;
	unsigned int *odr;
	struct Platform_data_spex *spex;
};
struct stm32mp157a *drv_led;
int drv_led_open(struct inode *ide, struct file *filp)
{
	int ret =0;
	printk("---%s---\r\n",__FUNCTION__);
	return ret;
}
	
int drv_led_close(struct inode *ide, struct file *filp)
{
	int ret =0;
	printk("---%s---\r\n",__FUNCTION__);
	return ret;
}
ssize_t drv_led_write(struct file *flp, const char __user *buf, size_t size , loff_t *flag)
{
	int ret =0;
	int led_status=0;
	printk("---%s---\r\n",__FUNCTION__);
	ret = copy_from_user(&led_status, buf, size);
	if(ret !=0)
	{
		printk("copy_from_user_err\r\n");
		return ret;
	}
	if(led_status == 0)	
	{
		*drv_led->odr &=~drv_led->spex->ODR_RESET;
	}
	else
	{
		*drv_led->odr |=drv_led->spex->ODR_RESET;
	}
	return ret;
}

const struct file_operations fops={
	.open = drv_led_open,
	.release = drv_led_close,
	.write = drv_led_write,
	
};

int drv_hello_probe(struct platform_device *pdev)
{
	int ret =0;
	printk("---%s---\r\n",__FUNCTION__);
	//实例化一个对象
	drv_led= kzalloc(sizeof(struct stm32mp157a), GFP_KERNEL);
	if(IS_ERR(drv_led))
	{
		printk("kzalloc_err\r\n");
		ret = PTR_ERR(drv_led);
		return ret;
	}
	drv_led->resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	printk("led_resource start=0x%x end=0x%x\r\n",drv_led->resource->start,drv_led->resource->end);

	drv_led->spex = pdev->dev.platform_data;
	printk("name=%s  minum=%d\r\n",drv_led->spex->name,drv_led->spex->minum);
	printk("modr_set=%d  modr_reset=%d\r\n",drv_led->spex->MODER_SET,drv_led->spex->MODER_RESET);
	printk("odr_set=%d  odr_reset=%d\r\n",drv_led->spex->ODR_SET,drv_led->spex->ODR_RESET);
	//申请设备号
	drv_led->major = register_chrdev(0, drv_led->spex->name, &fops);
	if(drv_led->major < 0)
	{
		printk("register_chrdev_err\r\n");
		goto register_chrdev_err;
	}
	//创建类
	drv_led->cls = class_create(THIS_MODULE, drv_led->spex->name);
	if(IS_ERR(drv_led->cls))
	{
		printk("class_create_err\r\n");
		ret = PTR_ERR(drv_led->cls);
		goto class_create_err;
	}
	//创建节点
	drv_led->dev = device_create(drv_led->cls, NULL, MKDEV(drv_led->major, drv_led->spex->minum), NULL, drv_led->spex->name);
	if(IS_ERR(drv_led->dev))
	{
		printk("device_create_err\r\n");
		ret = PTR_ERR(drv_led->dev);
		goto device_create_err;
	}
	//硬件初始化
	drv_led->mdr = ioremap(drv_led->resource->start, drv_led->resource->end - drv_led->resource->start);
	if(IS_ERR(drv_led->mdr))
	{
		printk("ioremap_err\r\n");
		ret = PTR_ERR(drv_led->mdr);
		goto ioremap_err;
	}
	drv_led->odr = drv_led->mdr +5;
	*drv_led->mdr &= ~drv_led->spex->MODER_RESET;
	*drv_led->mdr |= drv_led->spex->MODER_SET;

	*drv_led->odr &=~drv_led->spex->ODR_RESET; 
	
	return ret;
ioremap_err:
	device_destroy(drv_led->cls, MKDEV(drv_led->major, drv_led->spex->minum));	
device_create_err:
	class_destroy(drv_led->cls );
class_create_err:
	unregister_chrdev(drv_led->major,drv_led->spex->name);
register_chrdev_err:
	kfree(drv_led);
	return ret;	
}
int drv_hello_remove(struct platform_device *pdev)
{
	int ret =0;
	printk("---%s---\r\n",__FUNCTION__);
	iounmap(drv_led->mdr);
	device_destroy(drv_led->cls, MKDEV(drv_led->major, drv_led->spex->minum));
	class_destroy(drv_led->cls );
	unregister_chrdev(drv_led->major,drv_led->spex->name);
	kfree(drv_led);
	return ret;
}

struct platform_device_id hello_id_table[]={
	{"drv_hello",0x01},
};

struct platform_driver drv={
	.probe = drv_hello_probe,
	.remove = drv_hello_remove,
	.driver = {
		.name = "hello",
	},
	.id_table = hello_id_table,
};

static int __init drv_hello_init(void)
{
	int ret =0;
	printk("---%s---\r\n",__FUNCTION__);
	platform_driver_register(&drv);
	return ret;
}
void __exit drv_hello_exit(void)
{
	printk("---%s---\r\n",__FUNCTION__);
	platform_driver_unregister(&drv);
}

module_init(drv_hello_init);
module_exit(drv_hello_exit);
MODULE_LICENSE("GPL");

